﻿using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Queer.Util.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace Queer.Util.Helper
{
    /// <summary>
    /// 仓储方法扩展
    /// </summary>
    public static class IRepositoryHelper
    {
        #region 真实删除

        /// <summary>
        /// 批量删除，且数据存在才根据主键删除（立即提交）
        /// </summary>
        public async static Task BatchDeleteAsync<T>(this IRepository<T> Db, ICollection<long> ids) where T : class, IPrivateEntity, new()
        {
            if (ids.Count > 100)
                throw new BusinessException("本方法限定100条以内，如需大规模操作，请采用sql或大批量处理方法");

            foreach (var id in ids)
            {
                await Db.DeleteNowAsync(id);
            };
        }

        /// <summary>
        /// 批量删除，且数据存在才根据主键删除（立即提交）
        /// </summary>
        public async static Task BatchDeleteAsync<T>(this IRepository<T> Db, ICollection<long?> ids) where T : class, IPrivateEntity, new()
        {
            if (ids.Count > 100)
                throw new BusinessException("本方法限定100条以内，如需大规模操作，请采用sql或大批量处理方法");

            foreach (var id in ids)
            {
                await Db.DeleteNowAsync(id);
            };
        }

        /// <summary>
        /// 批量删除，且数据存在才根据主键删除（立即提交）
        /// </summary>
        public async static Task BatchDeleteAsync<T>(this IRepository<T> Db, ICollection<string> ids) where T : class, IPrivateEntity, new()
        {
            if (ids.Count > 100)
                throw new BusinessException("本方法限定100条以内，如需大规模操作，请采用sql或大批量处理方法");

            foreach (var id in ids)
            {
                await Db.DeleteNowAsync(id.ParseToLong());
            };
        }

        #endregion

        #region 伪删除

        /// <summary>
        /// 批量伪删除（立即提交）
        /// </summary>
        public async static Task BatchFakeDeleteAsync<T>(this IRepository<T> Db, ICollection<string> ids) where T : class, IPrivateEntity, new()
        {
            var _ids = ids.Select(a => a.ParseToLong()).ToList();
            await Db.BatchFakeDeleteAsync(_ids);
        }

        /// <summary>
        /// 批量伪删除（立即提交） -- 最终执行，限制：100条以内
        /// </summary>
        public async static Task BatchFakeDeleteAsync<T>(this IRepository<T> Db, ICollection<long> ids) where T : class, IPrivateEntity, new()
        {
            if (ids.Count > 100)
                throw new BusinessException("本方法限定100条以内，如需大规模操作，请采用sql或大批量处理方法");

            foreach (var id in ids)
            {
                // 参考furion旧版代码

                // 查找加删除特性
                var fakeDeleteProperty = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
                        .FirstOrDefault(u => u.IsDefined(typeof(FakeDeleteAttribute), true));

                if (fakeDeleteProperty == null) throw new InvalidOperationException("代码错误：该对象未设置删除键！");

                // 读取假删除的名和属性
                var fakeDeleteAttribute = fakeDeleteProperty.GetCustomAttribute<FakeDeleteAttribute>(true);
                var state = fakeDeleteAttribute.State;

                // 创建对象并设置属性值
                var entity = System.Activator.CreateInstance<T>();
                // 设置ID
                var idProperty = typeof(T).GetProperties().FirstOrDefault(u => u.Name == "Id");
                idProperty.SetValue(entity, id);
                // 设置删除
                fakeDeleteProperty.SetValue(entity, state);

                await entity.UpdateNowAsync(ignoreNullValues: true);
            };
        }

        /// <summary>
        /// 批量伪删除（立即提交）
        /// </summary>
        public async static Task BatchFakeDeleteAsync<T>(this IRepository<T> Db, ICollection<long?> ids) where T : class, IPrivateEntity, new()
        {
            var _ids = ids.Select(a => a.GetValueOrDefault()).ToList();
            await Db.BatchFakeDeleteAsync(_ids);
        }

        #endregion
    }


    /// <summary>
    /// 假删除/软删除
    /// </summary>
    [SuppressSniffer, AttributeUsage(AttributeTargets.Property)]
    public class FakeDeleteAttribute : Attribute
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="state"></param>
        public FakeDeleteAttribute(object state)
        {
            State = state;
        }

        /// <summary>
        /// 假删除/软删除状态
        /// </summary>
        public object State { get; set; }
    }
}